package cn.ljy.mes.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.ljy.authority.config.security.UserUtil;
import cn.ljy.authority.service.impl.IBaseService;
import cn.ljy.common.exception.model.MyServiceException;
import cn.ljy.common.exception.model.MyWebException;
import cn.ljy.mes.dao.mapper.*;
import cn.ljy.mes.model.*;
import cn.ljy.mes.model.common.enums.ReservationAction;
import cn.ljy.mes.model.query.MesCarTechnologyDetailQuery;
import cn.ljy.mes.model.query.MesProductionOrderStepQuery;
import cn.ljy.mes.service.MesProductionOrderStepService;
import cn.ljy.mes.service.WmsMaterialInventoryDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

@Service
public class IMesProductionOrderStepService extends IBaseService<MesProductionOrderStep, MesProductionOrderStepQuery> implements MesProductionOrderStepService {

    @Autowired
    private MesProductionOrderStepMapper mapper;
    @Autowired
    private MesProductionOrderMapper productionOrderMapper;
    @Autowired
    private MesProductionOrderStepAuditLogMapper productionOrderStepAuditLogMapper;
    @Autowired
    private ShopCarOrderMapper carOrderMapper;
    @Autowired
    private ShopCarProductMapper carProductMapper;
    @Autowired
    private MesCarModelConfigMapper carModelConfigMapper;
    @Autowired
    private MesCarModelMapper carModelMapper;
    @Autowired
    private MesCarTechnologyMapper carTechnologyMapper;
    @Autowired
    private MesCarTechnologyDetailMapper carTechnologyDetailMapper;
    @Autowired
    private WmsMaterialBatchMapper materialBatchMapper;
    //特别说明：因入库出库涉及业务算法比较复杂，这里破例直接调用库存业务类。
    //设计：如果在业务层上进行分层，那么mes模块在仓储模块只上。
    @Autowired
    private WmsMaterialInventoryDetailService materialInventoryDetailService;

    @Override
    protected void enrichEntityFields(MesProductionOrderStep productionOrderStep){
        if(productionOrderStep!=null){
            //获取车型

        }
    }

    //说明：任务步骤分为三步：1是创建步骤（正式生产前）、2是完成生产步骤（填写物料批次、数量），3是审核（审核通过完成步骤，审核失败重新开始生产）
    @Override
    protected void beforeSave(MesProductionOrderStep productionOrderStep) {
        //1.验证订单信息，并获取生产订单在系统中的信息
        if(productionOrderStep.getProductionOrder().getId()==null){
            throw new MyWebException("验证失败：生产订单id不能为空");
        }
        MesProductionOrder productionOrder = productionOrderMapper.findByIdNoRelation(productionOrderStep.getProductionOrder().getId());
        if(productionOrder==null){
            throw new MyWebException("验证失败：生产订单在系统中不存在");
        }else{
            if(productionOrder.getStatus().equals("completed")){
                throw new MyWebException(String.format("创建失败：生产订单（车辆VIN%s）已经完成生产！",productionOrder.getVin()));
            }else if(!productionOrder.getStatus().equals("in_progress")){
                throw new MyWebException(String.format("创建失败：生产订单（车辆VIN%s）目前状态不在生产状态,无法进行生产！",productionOrder.getVin()));
            }
        }
        //2.获取当前的生产步骤，并验证上一步是否已经完成
        MesProductionOrderStepQuery productionOrderStepQuery=new MesProductionOrderStepQuery();
        productionOrderStepQuery.setProductionOrder(productionOrder);
        productionOrder.setSteps(mapper.findAll(productionOrderStepQuery));
        int stepCount=productionOrder.getSteps().size();//获取当前已经完成的步骤数
        if(productionOrder.getSteps().size()>0){
            //获取最后一步状态
            MesProductionOrderStep lastStep=productionOrder.getSteps().get(stepCount-1);//获取最后一个步骤
            if(!lastStep.getStatus().equals("audit_passed")){
                throw new MyServiceException("创建失败：生产步骤必须审核完成才能开始下一个步骤");
            }
        }
        //3.获取工艺对应的生产步骤，获取下一步的生产步骤
        MesCarTechnologyDetailQuery carTechnologyDetailQuery=new MesCarTechnologyDetailQuery();
        carTechnologyDetailQuery.setCarTechnology(new MesCarTechnology(productionOrder.getTechnologyId()));
        List<MesCarTechnologyDetail> carTechnologyDetails = carTechnologyDetailMapper.findAll(carTechnologyDetailQuery);
        int carTechnologyDetailsCount=carTechnologyDetails.size();
        if(stepCount<carTechnologyDetailsCount){
            int carTechnologyDetailsIndex=stepCount+1;//开始下一步
            productionOrderStep.setCarTechnologyDetail(carTechnologyDetails.get(carTechnologyDetailsIndex-1)); //获取当前步骤的生产工艺详情
            productionOrderStep.setStatus("pending");
            productionOrderStep.setId(IdUtil.fastSimpleUUID());
        }else{
            throw new MyServiceException("创建失败：生产工单的所有步骤已经完成，无需再继续下一步！");
        }
    }

    //编辑：主要是用于生产步骤的操作，即在save已经添加了步骤的前提下，填写实际使用的物料批次和物料数量
    //说明：使用的物料数量需要从库存中扣除，也就是必须有出库过程。
    @Override
    public void update(MesProductionOrderStep productionOrderStep){
        //1.首先验证生产步骤信息
        if(!StringUtils.hasLength(productionOrderStep.getId())){//如果生产步骤ID不存在
            throw new MyWebException("验证失败：生产订单的步骤id不能为空");
        }
        //获取原来的生产步骤信息
        MesProductionOrderStep productionOrderStepOrignl = mapper.findById(productionOrderStep.getId());
        if(productionOrderStepOrignl==null){
            throw new MyWebException("验证失败：该生产步骤在系统中不存在");
        }else{
            if(!productionOrderStep.getProductionOrder().getStatus().equals("in_progress")){
                throw new MyWebException(String.format("操作失败：生产订单（车辆VIN%s）目前状态不满足生产要求,无法进行生产！",productionOrderStep.getProductionOrder().getVin()));
            }
            if(!productionOrderStepOrignl.getStatus().equals("in_progress")){
                throw new MyWebException(String.format("操作失败：该步骤目前无法变为完成状态"));
            }
        }
        //2.验证物料批次
        if(!StringUtils.hasLength(productionOrderStep.getMaterialBatch().getId())){//如果批次号ID不存在
            throw new MyWebException("验证失败：批次号的id不能为空");
        }
        WmsMaterialBatch materialBatch = materialBatchMapper.findById(productionOrderStep.getMaterialBatch().getId());
        if(materialBatch==null){
            throw new MyWebException("验证失败：物料批次在系统中不存在");
        }else{
            if(!materialBatch.getMaterial().getId().equals(productionOrderStepOrignl.getCarTechnologyDetail().getMaterial().getId())){
                throw new MyWebException("验证失败：选择的物料不符合工艺要求！");
            }
            if(materialBatch.getIsLock()){
                throw new MyWebException("验证失败：该物料批次已经被锁定，无法使用");
            }
            if(productionOrderStep.getActualQuantity()>materialBatch.getTotalInventory()){
                throw new MyWebException(String.format("验证失败：该物料批次库存数量不足%d个",materialBatch.getTotalInventory()));
            }
        }
        //3.设置并保存更新后的步骤信息
        productionOrderStepOrignl.setStatus("completed");//步骤为完成状态
        productionOrderStepOrignl.setMaterialBatch(materialBatch);//设置使用的物料批次
        productionOrderStepOrignl.setActualQuantity(productionOrderStep.getActualQuantity());//实际用量
        productionOrderStepOrignl.setOperator(UserUtil.getLoginUser());//设置操作员信息
        productionOrderStepOrignl.setEndTime(new Date());//设置完成时间
        //保存修改后的步骤信息
        mapper.update(productionOrderStepOrignl);
        //4.实现预出库操作(调用库存操作业务类）
        materialInventoryDetailService.reserveForOutboundByMaterialBatch(
                materialBatch,
                productionOrderStep.getActualQuantity(),
                String.format("将物料%s用于生产订单(%s)、车辆(VIN:%s)第%d步的生产",
                        materialBatch.getMaterial().getName(),
                        productionOrderStepOrignl.getProductionOrder().getId(),
                        productionOrderStepOrignl.getProductionOrder().getVin(),
                        productionOrderStep.getCarTechnologyDetail().getSort())
                );
    }


    @Override
    public void auditStep(String orderStepId, Boolean auditResult, String auditNote) {
        MesProductionOrderStep productionOrderStep = mapper.findById(orderStepId);
        if(productionOrderStep==null){
            throw new MyServiceException("操作失败：生产步骤在系统中不存在");
        }
        if(!productionOrderStep.getProductionOrder().getStatus().equals("in_progress")){
            throw new MyWebException(String.format("创建失败：生产订单（车辆VIN%s）目前状态不满足生产要求,无法进行生产！",productionOrderStep.getProductionOrder().getVin()));
        }
        if(productionOrderStep.getAuditResult()!=null&&productionOrderStep.getAuditResult()){
            throw new MyServiceException("操作失败：该生产步骤已经审核通过，无法再进行审核！");
        }
        if(auditResult){//如果审核通过
            //获取物料批次信息
            WmsMaterialBatch materialBatch = materialBatchMapper.findById(productionOrderStep.getMaterialBatchId());
            productionOrderStep.setMaterialBatch(materialBatch);
            productionOrderStep.setStatus("audit_passed");
            //完成物料的出库（将预出库转为出库）
            materialInventoryDetailService.settleReservationByMaterialBatch(
                    materialBatch,
                    ReservationAction.CONFIRM_OUTBOUND.name(),
                    productionOrderStep.getActualQuantity(),
                    String.format("将物料%s用于生产订单(%s)、车辆(VIN:%s)第%d步的生产中",
                            materialBatch.getMaterial().getName(),
                            productionOrderStep.getProductionOrder().getId(),
                            productionOrderStep.getProductionOrder().getVin(),
                            productionOrderStep.getCarTechnologyDetail().getSort())
            );
            //如果该步骤是生产工单的最后一步，审核通过后要将生产订单改为完成状态
            MesCarTechnologyDetailQuery carTechnologyDetailQuery=new MesCarTechnologyDetailQuery();
            carTechnologyDetailQuery.setCarTechnology(new MesCarTechnology(productionOrderStep.getProductionOrder().getTechnologyId()));
            int carTechnologyDetailNumber= carTechnologyDetailMapper.count(carTechnologyDetailQuery);
            if(productionOrderStep.getCarTechnologyDetail().getSort()==carTechnologyDetailNumber){
                //将生产订单状态改为完成状态
                MesProductionOrder productionOrder = productionOrderMapper.findByIdNoRelation(productionOrderStep.getProductionOrder().getId());
                productionOrder.setStatus("completed");
                Date now=new Date();
                productionOrder.setEndTime(now);
                productionOrderMapper.update(productionOrder);
            }
        }else{//如果审核不通过
            productionOrderStep.setStatus("audit_failed");
        }
        productionOrderStep.setAuditor(UserUtil.getLoginUser());//设置审核人信息
        productionOrderStep.setAuditResult(auditResult);//审核结果
        productionOrderStep.setAuditTime(new Date());//审核时间
        productionOrderStep.setAuditNote(auditNote);//审核意见
        //保存到数据库
        mapper.update(productionOrderStep);
        //记录到审核日志
        MesProductionOrderStepAuditLog productionOrderStepAuditLog=new MesProductionOrderStepAuditLog();
        productionOrderStepAuditLog.setId(IdUtil.fastSimpleUUID());
        productionOrderStepAuditLog.setProductionOrderStep(productionOrderStep);
        productionOrderStepAuditLog.setProductionOrder(productionOrderStep.getProductionOrder());
        productionOrderStepAuditLog.setMaterialBatch(productionOrderStep.getMaterialBatch());
        productionOrderStepAuditLog.setTechnologyDetail(productionOrderStep.getCarTechnologyDetail());
        productionOrderStepAuditLog.setActualQuantity(productionOrderStep.getActualQuantity());
        productionOrderStepAuditLog.setOperator(productionOrderStep.getOperator());
        productionOrderStepAuditLog.setStartTime(productionOrderStep.getStartTime());
        productionOrderStepAuditLog.setEndTime(productionOrderStep.getEndTime());
        productionOrderStepAuditLog.setAuditor(productionOrderStep.getAuditor());
        productionOrderStepAuditLog.setAuditResult(productionOrderStep.getAuditResult());
        productionOrderStepAuditLog.setAuditNote(productionOrderStep.getAuditNote());
        productionOrderStepAuditLog.setAuditTime(productionOrderStep.getAuditTime());
        productionOrderStepAuditLogMapper.save(productionOrderStepAuditLog);
    }

    @Override
    public void updateStepStatusToInProgress(String orderStepId) {
        MesProductionOrderStep productionOrderStep = mapper.findById(orderStepId);
        //1.生产步骤验证
        if(productionOrderStep==null){
            throw new MyServiceException("操作失败：生产步骤在系统中不存在");
        }
        if(productionOrderStep.getStatus().equals("pending")&&productionOrderStep.getStatus().equals("audit_failed")){
            throw new MyWebException(String.format("操作失败：该生产步骤无法开始生产"));
        }
        //2.如果是审核失败状态，将生产步骤中的已经使用的物料返回仓库（线边库）
        //获取已经使用的物料批次信息
        if(productionOrderStep.getMaterialBatchId()!=null){
            WmsMaterialBatch materialBatch = materialBatchMapper.findById(productionOrderStep.getMaterialBatchId());
            //完成物料的返回（将预出库转为撤销出库，即将锁定数量解锁）
            materialInventoryDetailService.settleReservationByMaterialBatch(
                    materialBatch,
                    ReservationAction.RELEASE_RESERVATION.name(),
                    productionOrderStep.getActualQuantity(),
                    String.format("将物料%s用于生产订单(%s)、车辆(VIN:%s)第%d步的生产中返还",
                            materialBatch.getMaterial().getName(),
                            productionOrderStep.getProductionOrder().getId(),
                            productionOrderStep.getProductionOrder().getVin(),
                            productionOrderStep.getCarTechnologyDetail().getSort())
            );
        }
        //3.清除之前使用的物料、生产操作和审核状态
        mapper.reset(orderStepId);
        //4.重新给生产步骤赋值
        productionOrderStep = mapper.findByIdNoRelation(orderStepId);
        productionOrderStep.setStatus("in_progress");//设置为生产状态
        productionOrderStep.setStartTime(new Date());
        mapper.update(productionOrderStep);
    }

}
